﻿using GN.Pay.TradeChannel.DefaultImpl;
using GN.Pay.TradeChannel.WeiXin.Response;
using GN.Pay.Utils;
using GN.Pay.Utils.Net.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace GN.Pay.TradeChannel.WeiXin.Request
{
    [Serializable]
    abstract class APayRequest : AServiceRequest
    {
        protected APayRequest(IChannel channel,
            IOrderPayApply order,
            WeiXinConfigure config)
        {
            init(channel, order, config);
        }

        /// <summary>
        /// 订单过期时间
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        protected string DiffDate(IOrderPayApply order)
        {
            var ts = order.ExpireTime - order.StartTime;
            if (ts.TotalMinutes > 0)
            {
                return ((int)ts.TotalMinutes).ToString() + "m";
            }
            return "";
        }


        /// <summary>
        /// 初始化请求参数配置
        /// </summary>
        /// <param name="channel">支付通道</param>
        /// <param name="order">订单详情</param>
        /// <param name="config">微信配置项</param>
        protected void init(IChannel channel,
            IOrderPayApply order,
            WeiXinConfigure config)
        {
            if (channel == null)
            {
                ExceptionUtils.CheckNotNull(channel, nameof(channel));
            }
            if (order == null)
            {
                channel.ThrowChannelValidationException("请求的 order 为 null");
            }
            if (config == null)
            {
                channel.ThrowChannelValidationException("请求的 config 为 null");
            }
            if (config.ConfigureInfo == null)
            {
                channel.ThrowChannelValidationException("请求的 config 的 ConfigureInfo 为 null");
            }
            this.Appid = config.ConfigureInfo.AppId;
            this.Mch_id = config.ConfigureInfo.AccountId;
            //Body实际应用超过64位就会出错 
            this.Body = FixedLengthString(order.Body, 32);
            this.Out_Trade_No = order.OrderNo;
            this.Total_Fee = GetMoneyForCent(order.OrderMoney);
            this.Spbill_Create_IP = order.ClientIP;
            this.Notify_url = config.PayNotifyUrl;
            this.Time_Start = order.StartTime.ToString("yyyyMMddHHmmss");
            this.Time_Expire = order.ExpireTime.ToString("yyyyMMddHHmmss");
        }

        /// <summary>
        /// 微信分配的公众账号ID（企业号corpid即为此appId） 
        /// </summary>
        public string Appid { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Time_Start { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Time_Expire { get; set; }

        /// <summary>
        /// 微信支付分配的商户号
        /// </summary>
        public string Mch_id { get; set; }

        /// <summary>
        /// 商品描述	body	必填	String(128)	腾讯充值中心-QQ会员充值	 商品简单描述，该字段须严格按照规范传递，具体请见参数规定
        /// </summary>
        public string Body { get; set; }

        /// <summary>
        /// 商户订单号	out_trade_no	必填	String(32)	20150806125346	商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
        /// </summary>
        public string Out_Trade_No { get; set; }

        /// <summary>
        /// 总金额	total_fee	必填	Int	888	订单总金额，单位为分，详见支付金额
        /// </summary>
        public long Total_Fee { get; set; }
        /// <summary>
        /// 终端IP	spbill_create_ip	必填	String(16)	123.12.12.123	APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP。
        /// </summary>
        public string Spbill_Create_IP { get; set; }

        /// <summary>
        /// 交易类型	trade_type	必填	String(16)	JSAPI	取值如下：JSAPI，NATIVE，APP，详细说明见参数规定
        /// </summary>
        public abstract string Trade_Type { get; }

        /// <summary>
        /// 通知地址
        /// </summary>
        public string Notify_url { get; set; }

        /// <summary>
        /// 创建响应
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        protected abstract PayResponse CreatePayResponse(string xml);

        public ITradePayApplyResult Build(ITradeChannel channel,
            WeiXinConfigure config, params string[] ingoreKey)
        {
            string resultXml = BuildSignXmlParam(channel, config, ingoreKey);
            string resultData = HttpUtils.PostString("https://api.mch.weixin.qq.com/pay/unifiedorder", resultXml);
            var res = CreatePayResponse(resultData);
            if (!res.IsReturnSuccess())
            {
                channel.ThrowChannelValidationException(res.Return_Msg);
            }
            if (!res.IsResultSuccess())
            {
                if (string.IsNullOrWhiteSpace(res.Err_Code_Des))
                {
                    channel.ThrowChannelValidationException(res.Err_Code_Des);
                }
                channel.ThrowChannelValidationException(res.Err_Code);
            }
            if (!res.SignVerify(config))
            {
                channel.ThrowSignFailException("签名未通过");
            }
            return res.ToResult(config);
        }
    }
}
